package com.echo.im.platform.service.impl;

import cn.dev33.satoken.temp.SaTempUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.echo.im.common.model.message.IMPrivateMessage;
import com.echo.im.common.model.message.IMSystemMessage;
import com.echo.im.common.model.IMUserInfo;
import com.echo.im.common.vo.ApplyFriendVO;
import com.echo.im.common.vo.FriendVO;
import com.echo.im.common.vo.HandlerFriendApplyVO;
import com.echo.im.common.vo.message.PrivateMessageVO;
import com.echo.im.common.vo.message.SystemMessageVO;
import com.echo.im.common.vo.UserVO;
import com.echo.im.platform.core.dto.ApplyFriendDto;
import com.echo.im.platform.core.common.ResultEnum;
import com.echo.im.platform.core.contant.RedisKey;
import com.echo.im.platform.core.context.SessionContext;
import com.echo.im.platform.core.context.UserSession;
import com.echo.im.platform.core.dto.HandlerFriendApplyDto;
import com.echo.im.platform.core.dto.temp.ApplyFriendTemp;
import com.echo.im.platform.core.enums.MessageStatus;
import com.echo.im.platform.core.enums.MessageType;
import com.echo.im.platform.core.exception.GlobalException;
import com.echo.im.platform.core.utils.Idgenerator;
import com.echo.im.platform.manager.FriendManager;
import com.echo.im.platform.manager.PrivateMessageManager;
import com.echo.im.platform.manager.SystemMessageManager;
import com.echo.im.platform.manager.UserManager;
import com.echo.im.platform.service.FriendService;
import com.echo.im.platform.service.UserService;
import com.echo.im.repository.dao.entity.Friend;
import com.echo.im.repository.dao.entity.User;
import com.echo.im.repository.dao.mapper.FriendMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author lxy
 * @date 2024-08-14
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class FriendServiceImpl extends ServiceImpl<FriendMapper, Friend> implements FriendService {

    private final SystemMessageManager systemMessageManager;
    private final FriendManager friendManager;
    private final UserManager userManager;

    /**
     * 更新好友信息
     * @param vo 包含需要更新的好友信息的实体
     */
    @Override
    public void update(FriendVO vo) {
        long userId = SessionContext.getSession().getUserId();

        friendManager.updateFriendData(userId,vo.getId(), vo.getNickName(), vo.getHeadImage());

    }


    /**
     * 删除好友
     * 1. 删除数据库
     * 2. 给自己的其他端发送信息
     * 3. 在每个端删除好友历史记录
     * 4. 不提醒被删除的好友，模拟微信，悄悄删除
     * 5. 当被删除方查询删除方的好友信息时，显示不是好友，或者当其发送消息的时候，返回红色感叹号
     * @param friendId 好友的ID
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delFriend(Long friendId) {
        UserSession session = SessionContext.getSession();

        friendManager.checkFriend(session.getUserId(), friendId);

        // 互相解除好友关系，走代理清理缓存
        friendManager.unbindFriend(session.getUserId(), friendId);
        friendManager.unbindFriend(friendId, session.getUserId());

        //给自己的其他端发送信息
        //构造 PrivateMessage
        SystemMessageVO systemMessageVO = SystemMessageVO.builder()
                .id(Idgenerator.getMsgId())
                .recvId(session.getUserId())
                .type(MessageType.DEL_FRIEND.code())
                .content(friendId.toString())
                .sendTime(new Date()).build();

        IMSystemMessage imSystemMessage = new IMSystemMessage();
        imSystemMessage.setRecvIds(Collections.singletonList(session.getUserId()));
        imSystemMessage.setData(systemMessageVO);

        systemMessageManager.sendAndSave(imSystemMessage);

        log.info("删除好友，用户id:{},好友id:{}", session.getUserId(), friendId);
    }

    /**
     * 查找好友
     * @param friendId 好友的ID
     * @return 好友信息
     */
    @Override
    public FriendVO findFriend(Long friendId) {
        UserSession session = SessionContext.getSession();

        Friend friend = friendManager.findFriend(session.getUserId(), friendId);

        FriendVO vo = new FriendVO();
        vo.setId(friend.getFriendId());
        vo.setHeadImage(friend.getFriendHeadImage());
        vo.setNickName(friend.getFriendNickName());

        return vo;
    }

    /**
     * 申请添加好友
     */
    @Override
    public void applyAddFriend(ApplyFriendDto dto) {
        UserSession session = SessionContext.getSession();
        //检查是不是好友、是不是黑名单
        //TODO
        //发送申请
        User user = userManager.getById(dto.getUserId());

        UserVO userVO = UserVO.builder().sex(user.getSex())
                .headImageThumb(user.getHeadImageThumb())
                .nickName(user.getNickName())
                .signature(user.getSignature())
                .build();

        //基于自己的userId构造临时token
        ApplyFriendTemp applyFriendTemp = new ApplyFriendTemp();
        applyFriendTemp.setOwner(session.getUserId());
        applyFriendTemp.setUser(dto.getUserId());
        String tempToken = SaTempUtil.createToken("addFriend",applyFriendTemp, 200);

        //构造消息内容
        ApplyFriendVO applyFriendVO = new ApplyFriendVO();
        applyFriendVO.setTempToken(tempToken);
        applyFriendVO.setUser(userVO);
        applyFriendVO.setApplyContent(dto.getApplyContent());

        //构造 系统消息
        SystemMessageVO systemMessageVO = SystemMessageVO.builder()
                .id(Idgenerator.getMsgId())
                .recvId(dto.getUserId())
                .type(MessageType.APPLY_ADD_FRIEND.code())
                //用户信息
                .content(JSON.toJSONString(applyFriendVO))
                .sendTime(new Date()).build();

        IMSystemMessage imSystemMessage = new IMSystemMessage();
        imSystemMessage.setRecvIds(Collections.singletonList(systemMessageVO.getRecvId()));
        imSystemMessage.setData(systemMessageVO);

        systemMessageManager.sendAndSave(imSystemMessage);
    }

    /**
     * 处理好友申请
     * 1. 去redis查看申请是否过期
     * 2. 如果是统一申请，则将好友关系入库
     * 3. 给对方回执
     * @param dto
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void handlerFriendApply(HandlerFriendApplyDto dto) {
        UserSession session = SessionContext.getSession();

        //解析临时token
        ApplyFriendTemp applyFriendTemp = SaTempUtil.parseToken("applyFriend",dto.getTempToken(), ApplyFriendTemp.class);
        if (Objects.isNull(applyFriendTemp)){
            throw new GlobalException(ResultEnum.NO_PERMISSION);
        }

        //验证token有消息
        if(!applyFriendTemp.getUser().equals(session.getUserId())||!applyFriendTemp.getOwner().equals(dto.getTargetUserId())){
            throw new GlobalException(ResultEnum.NO_PERMISSION);
        }

        Long friendId = dto.getTargetUserId();
        Boolean isAgree = dto.getIsAccept();

        if(isAgree){
            //添加好友逻辑入库
            friendManager.bindFriend(session.getUserId(), friendId);
            friendManager.bindFriend(friendId, session.getUserId());
            log.info("添加好友，用户id:{},好友id:{}", session.getUserId(), friendId);
        }

        //发送回执消息
        User user = userManager.getById(session.getUserId());

        UserVO userVO = UserVO.builder().sex(user.getSex())
                .headImageThumb(user.getHeadImageThumb())
                .nickName(user.getNickName())
                .signature(user.getSignature())
                .build();

        HandlerFriendApplyVO handlerFriendApplyVO = new HandlerFriendApplyVO();
        handlerFriendApplyVO.setHandlerUser(userVO);
        handlerFriendApplyVO.setIsAccept(isAgree);
        handlerFriendApplyVO.setContent(dto.getContent());

        //构造 SystemMessageVO
        SystemMessageVO systemMessageVO = SystemMessageVO.builder().build();
        systemMessageVO.setId(Idgenerator.getMsgId());
        systemMessageVO.setRecvId(friendId);
        systemMessageVO.setType(isAgree ? MessageType.AGREE_FRIEND_APPLY.code() : MessageType.REFUSE_FRIEND_APPLY.code());
        systemMessageVO.setContent(JSON.toJSONString(handlerFriendApplyVO));
        systemMessageVO.setSendTime(new Date());

        IMSystemMessage imSystemMessage = new IMSystemMessage();

        imSystemMessage.setSender(new IMUserInfo(session.getUserId(), session.getTerminal()));
        imSystemMessage.setFirstRecvId(systemMessageVO.getRecvId());
        imSystemMessage.setSendToSelf(false);
        imSystemMessage.setData(systemMessageVO);
        imSystemMessage.setSendResult(false);

        systemMessageManager.sendAndSave(imSystemMessage);
    }

    @Override
    public List<FriendVO> findFriendList() {
        SessionContext.getSession().getUserId();
        List<Friend> friends = friendManager.findFriendByUserId(SessionContext.getSession().getUserId());
        List<FriendVO> vos = friends.stream().map(f -> {
            FriendVO vo = new FriendVO();
            vo.setId(f.getFriendId());
            vo.setHeadImage(f.getFriendHeadImage());
            vo.setNickName(f.getFriendNickName());
            return vo;
        }).collect(Collectors.toList());
        return vos;
    }


}
